package com.newvpn.fastbest.zenith.presenter;

import static com.newvpn.fastbest.zenith.presenter.VPNReulst.STATE_CONNECTING;
import static com.newvpn.fastbest.zenith.presenter.VPNReulst.STATE_CONNECT_NEXT;
import static com.newvpn.fastbest.zenith.presenter.VPNReulst.STATE_DISCONNECT;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.google.gson.Gson;
import com.newvpn.fastbest.zenith.BuildConfig;
import com.newvpn.fastbest.zenith.R;
import com.newvpn.fastbest.zenith.VPNApp;
import com.newvpn.fastbest.zenith.activity.BaseActivity;
import com.newvpn.fastbest.zenith.activity.MainActivity;
import com.newvpn.fastbest.zenith.beans.netbeans.AdConfigBean;
import com.newvpn.fastbest.zenith.beans.netbeans.BaseResponse;
import com.newvpn.fastbest.zenith.beans.netbeans.EncryBean;
import com.newvpn.fastbest.zenith.beans.netbeans.NetServerListBean;
import com.newvpn.fastbest.zenith.beans.netbeans.PingBean;
import com.newvpn.fastbest.zenith.beans.netbeans.StartBean;
import com.newvpn.fastbest.zenith.beans.netbeans.UserInfo;
import com.newvpn.fastbest.zenith.beans.netbeans.VpnInfo;
import com.newvpn.fastbest.zenith.beans.reqbeans.NodeBean;
import com.newvpn.fastbest.zenith.net.NetService;
import com.newvpn.fastbest.zenith.notify.DisConnectNotifyHelper;
import com.newvpn.fastbest.zenith.utils.AdSwith;
import com.newvpn.fastbest.zenith.utils.DecryptUtils;
import com.newvpn.fastbest.zenith.utils.TestSpeedUtils;
import com.newvpn.fastbest.zenith.utils.ToastUtils;
import com.newvpn.fastbest.zenith.utils.VLog;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.schedulers.Schedulers;

@SuppressLint("CheckResult")
public class MainActivityPresenter {

    public static final int REQUEST_PERSSION_VPN_1 = 1001;
    public static final int REQUEST_PERSSION_VPN_2 = 1001;

    public static final int REQUEST_PERSSION_NOTIFY = 1003;

    private final int ONE_TIME = 15 * 1000;
    private final int ALL_TIME = 90 * 1000;
    private final int AD_WAIT_TIME = 5 * 1000;

    private BaseActivity mActivity;

    public void init(MainActivity activity) {
        mActivity = activity;
        VPNPresenter.INSTANCE.init(activity);
    }

    public void initNet() {
        NetService.INSTANCE.init(BuildConfig.NET_URL);

    }

    public void initToken(boolean isFirst) {
        VLog.e("initToken");
        NetService.INSTANCE.getUserInfo().subscribe(new Consumer<BaseResponse<UserInfo>>() {
            @Override
            public void accept(BaseResponse<UserInfo> userInfoBaseResponse) throws Throwable {
                UserInfo userInfo = userInfoBaseResponse.result;
                NetService.INSTANCE.updateToken(userInfo.token);
                afterGetToken();
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Throwable {
                if (isFirst) {
                    afterGetToken();
                }
                VLog.e("initToken error:" + throwable.getMessage());
                Observable.timer(3, TimeUnit.SECONDS)
                        .subscribeOn(Schedulers.io()) // 在 IO 线程上执行
                        .observeOn(Schedulers.computation()) // 在计算线程上观察
                        .subscribe(
                                aLong -> {
                                    initToken(false);
                                },
                                throwable1 -> {
                                    // 处理错误
                                    System.err.println("Error: " + throwable.getMessage());
                                }
                        );
            }
        });
    }

    private void afterGetToken() {
        VLog.e("afterGetToken()");
        NetService.INSTANCE.getAdConfig().subscribe(new Consumer<BaseResponse<EncryBean>>() {
            @Override
            public void accept(BaseResponse<EncryBean> encryBeanBaseResponse) throws Throwable {
                String info = DecryptUtils.decode(encryBeanBaseResponse.result);//"Ho8GkZqbZfGmILvU"
                Gson gson = new Gson();
                AdConfigBean bean = gson.fromJson(info, new com.google.gson.reflect.TypeToken<AdConfigBean>() {
                }.getType());
                if (bean == null) {
                    return;
                }
                AdConfigBean.AdConfig config = bean.ad_config;
                if (config == null) {
                    return;
                }

                if (config.before_connect != null) {
                    AdPresenter.INSTANCE.getAdConfigUtils().
                            loadBeforeAdIDs(getAdID(config.before_connect.interstitial),
                                    getAdID(config.before_connect.splash),
                                    getAdID(config.before_connect.nativeAd));
                }

                if (config.after_connect != null) {
                    AdPresenter.INSTANCE.getAdConfigUtils().loadAfterAdIDs(getAdID(config.after_connect.interstitial),
                            getAdID(config.after_connect.splash),
                            getAdID(config.after_connect.nativeAd));
                }
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Throwable {
                VLog.e("getAdConfig Error: " + throwable.getMessage());
                Observable.timer(60, TimeUnit.SECONDS)
                        .subscribeOn(Schedulers.io()) // 在 IO 线程上执行
                        .observeOn(Schedulers.computation()) // 在计算线程上观察
                        .subscribe(
                                aLong -> {
                                    afterGetToken();
                                },
                                throwable1 -> {
                                    // 处理错误
                                    System.err.println("Error: " + throwable.getMessage());
                                }
                        );

            }
        });
    }

    private String getAdID(List<AdConfigBean.AdInfo> list) {
        if (list == null || list.size() == 0) {
            return "";
        }
        int size = list.size();
        Random random = new Random();
        AdConfigBean.AdInfo info = list.get(random.nextInt(size));
        if (info == null) {
            return "";
        }
        return info.ad_unit_id;

    }


    public int getVPNStatus() {
        return VPNPresenter.INSTANCE.getVPNStatus();
    }

    public void vpnAction(MainActivity activity, VPNDetailInfo vpnDetailInfo, String scence, VPNActionCallback callback, boolean reConnectNewVPN) {
        VLog.e("VPNReulst："+getVPNStatus());
        if (getVPNStatus() == VPNReulst.STATE_DISCONNECT) {
            //mSSManager.startVPN(null,null);
            vpnStartAction(activity, vpnDetailInfo, scence, callback);
        } else if (getVPNStatus() == VPNReulst.STATE_CONNECTED) {
            vpnEndAction(activity, scence, callback,reConnectNewVPN);
        }
    }

    private void vpnEndAction(MainActivity activity, String scence, VPNActionCallback callback,boolean reConnectNewVPN) {
        VLog.e("vpnEndAction:reConnectNewVPN"+reConnectNewVPN);
        if (reConnectNewVPN){
            vpnEndActionNoAd(activity, scence, callback);
            return;
        }
        if (AdSwith.hideAdAfterDisConneted){
            vpnEndActionNoAd(activity, scence, callback);
            return;
        }
        mActivity.showLoading();
        AdPresenter.INSTANCE.loadAD(activity, scence, new AdPresenter.LoadAdCallback() {
            @Override
            public void beginLoad() {

            }

            @Override
            public void showAdResult(boolean success) {
                VLog.e("showAdResult：" + success);
                mActivity.endLoading();
                vpnEndActionNoAd(activity, scence, callback);
            }

            @Override
            public void endLoad(boolean success) {
                if (!success) {
                    mActivity.endLoading();
                    vpnEndActionNoAd(activity, scence, callback);
                }
            }

        }, System.currentTimeMillis(), 3 * 1000);
    }

    public String getConnectedCountry() {
        VPNDetailInfo vpnDetailInfo = VPNPresenter.INSTANCE.getConnectedVpnInfoServer();
        if (vpnDetailInfo == null) {
            vpnDetailInfo  = VPNPresenter.INSTANCE.getConnectingVpnInfoServer();
        }
        if (vpnDetailInfo == null) {
            return "";
        }
        return vpnDetailInfo.countryName;
    }

    public String getConnectedCountryUrl() {
        VPNDetailInfo vpnDetailInfo = VPNPresenter.INSTANCE.getConnectedVpnInfoServer();
        if (vpnDetailInfo == null) {
            vpnDetailInfo  = VPNPresenter.INSTANCE.getConnectingVpnInfoServer();
        }
        if (vpnDetailInfo == null) {
            return "";
        }
        return vpnDetailInfo.iconUrl;
    }


    public void vpnEndActionNoAd(MainActivity activity, String scence, VPNActionCallback callback) {
        VLog.e("vpnEndActionNoAd" );
        activity.showDisLoading();
        VPNPresenter.INSTANCE.disConnectAction();
        afterDisConnect(VPNPresenter.INSTANCE.getCurrServerId());
        //VPNPresenter.INSTANCE.setVpnStatus(VPNPresenter.INSTANCE.STATE_DISCONNECT);
        //callback.disconect();
        //        VPNPresenter.INSTANCE.disConnect(new VPNPresenter.ConnectBestCallback() {
//            @Override
//            public void success() {
//
//            }
//
//            @Override
//            public void fail(int errorCode) {
//                callback.error("VPN disConnection Failed：" + errorCode);
//
//            }
//        });
    }

//    private void vpnStartAction(MainActivity activity,VPNDetailInfo info, String scence, VPNActionCallback callback) {
//        vpnStartAction(activity,info,scence,callback,REQUEST_PERSSION_VPN_1);
//    }

    public void vpnStartAction(MainActivity activity, VPNDetailInfo info, String scence, VPNActionCallback callback) {
        //判断权限
        VLog.e("start vpn action");
        callback.connecting();
        boolean isSingleTask = !(info == null || TextUtils.isEmpty(info.serverId));
        startProcess(callback, isSingleTask);
        VPNPresenter.INSTANCE.beginConnect();
        //广告
        AdPresenter.INSTANCE.loadAD(activity, scence, new AdPresenter.LoadAdCallback() {
            @Override
            public void beginLoad() {

            }

            @Override
            public void showAdResult(boolean success) {

            }

            @Override
            public void endLoad(boolean success) {
                if (!isSingleTask) {
                    //自动连接，获取VPN信息
                    getVPNListInfo(callback);
                } else {
                    long session = VPNPresenter.INSTANCE.preStartAction();
                    VPNPresenter.INSTANCE.setConnectingVpnInfoServer(info);
                    Log.e("setConnectedVpnInfoServer","vpnStartAction,endLoad,isSingleTask",null);
                    VPNPresenter.INSTANCE.setConnectedVpnInfoServer(null);
                    afterTestVPNSpeed(session, info, callback);
                }


            }
        }, 0, 0);

    }

    Disposable vpnProcessDisposable;

    private void diposeVpnProcess() {
        if (vpnProcessDisposable != null) {
            vpnProcessDisposable.dispose();
        }
    }

    //private long allStartTime = 0;
    private long onceStartTime = 0;

    private void startProcess(VPNActionCallback callback, boolean isSingleTask) {
        diposeVpnProcess();
        int period = 100;
        long oneLoadVPNtime = ONE_TIME;
        long oneLoadAlltime = ONE_TIME + AD_WAIT_TIME;
        int allCount = ALL_TIME / period;
        //int oneCount = (int)((oneLoadAlltime) / period);
        //allStartTime = System.currentTimeMillis();
        onceStartTime = System.currentTimeMillis();
        if (vpnProcessDisposable != null) {
            vpnProcessDisposable.dispose();
        }
        vpnProcessDisposable = Observable.interval(0, period, TimeUnit.MILLISECONDS)
                .take(allCount)
                .subscribeOn(Schedulers.io()) // 在IO线程执行
                .observeOn(AndroidSchedulers.mainThread()) // 观察在单线程中执行
                .subscribe(
                        number -> {
                            //long num = number + 1;
                            int status = VPNPresenter.INSTANCE.getVPNStatus();
                            if (status == VPNReulst.STATE_CONNECTING || status == VPNReulst.STATE_CONNECTED_LOADADING) {
                                //连接状态or广告加载中状态
                            } else if (status == VPNReulst.STATE_CONNECTED) {
                                //已连接
                                VLog.e("STATE_CONNECTED");
                                callback.conected();
                                diposeVpnProcess();
                                return;
                            } else if (status == VPNReulst.STATE_CONNECTED_PRE) {
                                //v连接上了，准备加载广告
                                VLog.e("begin load ad");
                                VPNPresenter.INSTANCE.setVpnStatus(VPNReulst.STATE_CONNECTED_LOADADING);
                                VPNDetailInfo server = VPNPresenter.INSTANCE.getConnectedVpnInfoServer();
                                afterConntedShowAd(server, callback);
                            } else if (status == STATE_CONNECT_NEXT) {
                                //超时或者异常下一个
                                if (mTryOtherServiceCallback != null) {
                                    VLog.e("vpn try other");
                                    VPNPresenter.INSTANCE.setVpnStatus(VPNReulst.STATE_CONNECTING);
                                    mTryOtherServiceCallback.tryOther();
                                }
                                return;
                            } else {
                                //未连接状态
                                callback.disconect(false);
                                vpnProcessDisposable.dispose();
                                return;
                            }
                            long diffTime = System.currentTimeMillis() - onceStartTime;
                            long showdiffTime = diffTime % oneLoadAlltime;
                            int processInt = (int) ((showdiffTime * 1.0f / oneLoadAlltime) * 100);
                            callback.onProcess(processInt + "");
                            if (diffTime >= oneLoadAlltime) {
                                //超过了单次总时间
                                if (status == VPNReulst.STATE_CONNECTING) {
                                    //超时，下一个
                                    VLog.e("single task time out");
                                    if (!isSingleTask) {
                                        VPNPresenter.INSTANCE.setVpnStatus(STATE_CONNECT_NEXT);
                                    } else {
                                        VPNPresenter.INSTANCE.setVpnStatus(STATE_DISCONNECT);
                                    }
                                } else if (status == VPNReulst.STATE_CONNECTED_LOADADING) {
                                    //v成功，广告不成功，显示连接成功
                                    VLog.e("vpn sucess ,ad load fail");
                                    VPNDetailInfo server = VPNPresenter.INSTANCE.getConnectedVpnInfoServer();
                                    callback.conected();
                                    VPNPresenter.INSTANCE.setVpnStatus(VPNReulst.STATE_CONNECTED);
                                    if (server != null) {
                                        VPNPresenter.INSTANCE.afterConnected(server.serverId);
                                        sessionStartAndCoundown(server.serverId);
                                    }
                                    diposeVpnProcess();
                                }
                            } else if (diffTime >= oneLoadVPNtime) {
                                //超过了单次v时间，如果v还没连上，则下一个
                                if (status == VPNReulst.STATE_CONNECTING) {
                                    //超时，下一个
                                    VLog.e("single task out time");
                                    onceStartTime = System.currentTimeMillis();
                                    if (!isSingleTask) {
                                        VPNPresenter.INSTANCE.setVpnStatus(STATE_CONNECT_NEXT);
                                    } else {
                                        VPNPresenter.INSTANCE.setVpnStatus(STATE_DISCONNECT);
                                        callback.error(VPNApp.getBase().getString(R.string.try_again));
                                    }
                                }
                            }
//
                        },
                        Throwable::printStackTrace,
                        () -> {
                            //结束状态，判断当前v状态是否已经连接
                            VLog.e("all task timeout");
                            int status = VPNPresenter.INSTANCE.getVPNStatus();
//                            if (status == VPNReulst.STATE_CONNECTING) {
//                                VPNPresenter.INSTANCE.disConnectAction();
//                                connectError(callback, "超时了");
//                                Log.e("NewVPN1", "整体超时处理");
//                            } else
                            if (status == VPNReulst.STATE_CONNECTED || status == VPNReulst.STATE_CONNECTED_PRE
                                    || status == VPNReulst.STATE_CONNECTED_LOADADING) {
                                //v连接成功，不管广告状态了，直接结束
                                VPNDetailInfo server = VPNPresenter.INSTANCE.getConnectedVpnInfoServer();
                                callback.conected();
                                if (server != null) {
                                    VPNPresenter.INSTANCE.afterConnected(server.serverId);
                                    sessionStartAndCoundown(server.serverId);
                                }
                            } else {
                                callback.disconect(true);
                                VPNPresenter.INSTANCE.disConnectAction();
                                VPNPresenter.INSTANCE.afterDisConnect();
                                connectError(callback, VPNApp.getBase().getString(R.string.try_again));
                                VLog.e("all task time out");
                            }
                            diposeVpnProcess();
                        }
                );

    }


    @SuppressLint("CheckResult")
    private void getVPNListInfo(VPNActionCallback callback) {

        List<VpnInfo> list = VPNPresenter.INSTANCE.getAllList();
        if (list !=null){
            afterGetVPNList(list,callback);
            return;
        }
        NetService.INSTANCE.getVPNList().subscribe(new Consumer<BaseResponse<EncryBean>>() {
            @Override
            public void accept(BaseResponse<EncryBean> encryBeanBaseResponse) throws Throwable {
                EncryBean data = encryBeanBaseResponse.result;
                String passwordDecrypt = DecryptUtils.decodeRSA(data.password);
                String info = DecryptUtils.decodeAES(passwordDecrypt, data.content);//"Ho8GkZqbZfGmILvU"
                Gson gson = new Gson();
                List<VpnInfo> list = gson.fromJson(info, new com.google.gson.reflect.TypeToken<List<VpnInfo>>() {
                }.getType());
                VPNPresenter.INSTANCE.setAllList(list);
                afterGetVPNList(list,callback);

            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Throwable {
                VLog.e("getVPNList error");
                diposeVpnProcess();
                connectError(callback, VPNApp.getBase().getString(R.string.try_again));
            }
        });
    }

    private void afterGetVPNList(List<VpnInfo> list,VPNActionCallback callback){
        currConnectingList = list;
        //List<NetNodeListBean.Node> list = response.data;
        //VpnManager.INSTANCE.setServiceList(getApplicationContext(), list);
        testVPNSpeed(list, callback);
    }

    private interface TryOtherServiceCallback {
        void tryOther();
    }

    private TryOtherServiceCallback mTryOtherServiceCallback = new TryOtherServiceCallback() {
        @Override
        public void tryOther() {
            ToastUtils.show(R.string.try_next_server);
            if (currConnectingList == null) {
                VLog.e("currConnectingList == null");
                return;
            }

            if (currVPNActionCallback == null) {
                VLog.e("currVPNActionCallback == null");
                return;
            }
            VPNPresenter.INSTANCE.disConnectAction();
            testVPNSpeed(currConnectingList, currVPNActionCallback);

        }
    };

    private List<VpnInfo> currConnectingList;
    private VPNActionCallback currVPNActionCallback;
    private String currService;

    private void clearCurrInfos() {
        currConnectingList = null;
        currVPNActionCallback = null;
        currService = null;
    }


    boolean hasGetPingReuslt;

    private void testVPNSpeed(List<VpnInfo> list, VPNActionCallback callback) {
        VLog.e("testVPNSpeed");
        long session = VPNPresenter.INSTANCE.preStartAction();
        TestSpeedUtils testSpeedUtils = new TestSpeedUtils();
        hasGetPingReuslt = false;
        testSpeedUtils.testSpeed(list, currService, new TestSpeedUtils.Callback() {
            @Override
            public void onResult(VPNDetailInfo server) {
                if (VPNPresenter.INSTANCE.getCurrConnectSession() != session) {
                    return;
                }
                if (server == null) {
                    VLog.e("ping timeout");
                    connectError(callback, "net error");
                    return;
                }
                if (hasGetPingReuslt){
                    VLog.e("ping: not work");
                    return;
                }
                hasGetPingReuslt = true;
                VLog.e("ping:" + server.getPingTime());
                currVPNActionCallback = callback;
                currService = server.serverId;
                VPNPresenter.INSTANCE.setConnectingVpnInfoServer(server);
                Log.e("setConnectedVpnInfoServer","testVPNSpeed onreuslt",null);
                VPNPresenter.INSTANCE.setConnectedVpnInfoServer(null);
                afterTestVPNSpeed(session, server, callback);
            }
        });
    }

    private void connectError(VPNActionCallback callback, String error) {
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                VPNPresenter.INSTANCE.afterDisConnect();
                callback.error(error);
                callback.disconect(true);
            }
        });

    }

    //VPNDetailInfo vpnDetailInfo;

    @SuppressLint("CheckResult")
    private void afterTestVPNSpeed(long session, VPNDetailInfo server, VPNActionCallback callback) {
        VLog.e("afterTestVPNSpeed");
        NodeBean bean = new NodeBean();
        bean.serverId = server.serverId;

        NetService.INSTANCE.geVPNServerInfo(bean)
                .retryWhen(attempts -> attempts
                        .zipWith(Observable.range(0, 4), (error, count) -> count) // 总共尝试4次，包括初次尝试
                        .flatMap(attempt -> {
                            if (attempt >= 3) { // 第三次重试失败后执行其他操作
                                VLog.e("afterTestVPNSpeed:" + attempt);
                                return Observable.error(new Exception("Max retries reached"));
                            } else {
                                return Observable.timer(1, TimeUnit.SECONDS); // 设置重试间隔
                            }
                        }))
                .subscribe(new Consumer<BaseResponse<EncryBean>>() {
                    @Override
                    public void accept(BaseResponse<EncryBean> response) throws Throwable {
                        if (VPNPresenter.INSTANCE.getCurrConnectSession() != session) {
                            return;
                        }
                        if (response.code == 30003) {
                            VLog.event("Time_Exhausted");
                            //connectVpnError(virtualProgressManager);
                            //ToastUtils.show(response.m);
                            callback.error(response.msg);
                            diposeVpnProcess();
                            return;
                        }
                        EncryBean data = response.result;
                        String passwordDecrypt = DecryptUtils.decodeRSA(data.password);
                        String info = DecryptUtils.decodeAES(passwordDecrypt, data.content);//"Ho8GkZqbZfGmILvU"
                        Gson gson = new Gson();
                        NetServerListBean dataBean = gson.fromJson(info, NetServerListBean.class);
                        List<NetServerListBean.ServiceInfoDetail> list = dataBean.accessKey;
                        VLog.e("connectBest begin：" + dataBean.serverIp + "," + list.get(0).port + "," + list.get(0).password + "," + list.get(0).method);

                        VPNPresenter.INSTANCE.connectBest(server, session, dataBean.serverIp, list.get(0), new VPNPresenter.ConnectBestCallback() {
                            @Override
                            public void success(VPNDetailInfo vpnDetailInfo) {
                                if (VPNPresenter.INSTANCE.getCurrConnectSession() != session) {
                                    return;
                                }
                                if (VPNPresenter.INSTANCE.getVPNStatus() != STATE_CONNECTING) {
                                    VPNPresenter.INSTANCE.disConnectAction();
                                    return;
                                }
                                Log.e("setConnectedVpnInfoServer","connectBest success:"+VPNPresenter.INSTANCE.getConnectingVpnInfoServer());
                                VPNPresenter.INSTANCE.setConnectedVpnInfoServer(VPNPresenter.INSTANCE.getConnectingVpnInfoServer());
                                VLog.e("connectBest success");
                                //VPNPresenter.INSTANCE.setCurrServerId(server.serverId);
                                VPNPresenter.INSTANCE.setVpnStatus(VPNReulst.STATE_CONNECTED_PRE);
                                if (mVPNInfoCallback != null) {
                                    mVPNInfoCallback.updateRecommon(VPNPresenter.INSTANCE.getConnectedVpnInfoServer());
                                }
                                //diposeVpnProcess();
                            }

                            @Override
                            public void fail(int error) {
                                if (VPNPresenter.INSTANCE.getCurrConnectSession() != session) {
                                    return;
                                }
                                VLog.e("connectBest error:" + error);
//                        callback.disconect();
//                        callback.error("net error:" + error);
//                        VPNPresenter.INSTANCE.afterDisConnect();

                                VPNDetailInfo info = server;
                                if (info == null || TextUtils.isEmpty(info.serverId)) {
                                    VPNPresenter.INSTANCE.setVpnStatus(STATE_CONNECT_NEXT);
                                } else {
                                    ToastUtils.show(R.string.try_again);
                                    VPNPresenter.INSTANCE.setVpnStatus(VPNReulst.STATE_DISCONNECT);
                                }
                                //diposeVpnProcess();
                            }

                            @Override
                            public void trafficUpdated(long txRate, long rxRate) {
                                callback.trafficUpdated(txRate, rxRate);
                            }

                            @Override
                            public void stop() {
                                callback.disconect(false);
                            }
                        }, false);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Throwable {
//                callback.error(throwable.getMessage());
//                callback.disconect();
                    }
                });

    }

    private void afterConntedShowAd(VPNDetailInfo server, VPNActionCallback callback) {
        AdPresenter.INSTANCE.loadAD(mActivity, "Interstitial_Click_Connet", new AdPresenter.LoadAdCallback() {
            @Override
            public void beginLoad() {

            }

            @Override
            public void showAdResult(boolean success) {
                if (VPNPresenter.INSTANCE.getVPNStatus() != VPNReulst.STATE_CONNECTED) {
                    VPNPresenter.INSTANCE.setVpnStatus(VPNReulst.STATE_CONNECTED);
                    callback.conected();
                    if (server !=null){
                        VPNPresenter.INSTANCE.afterConnected(server.serverId);
                        sessionStartAndCoundown(server.serverId);
                    }
                    VLog.e("vpn afterConntedShowAd show result:" + success);
                }
            }

            @Override
            public void endLoad(boolean success) {
                if (!success) {
                    if (VPNPresenter.INSTANCE.getVPNStatus() != VPNReulst.STATE_CONNECTED) {
                        VPNPresenter.INSTANCE.setVpnStatus(VPNReulst.STATE_CONNECTED);
                        callback.conected();
                        if (server !=null){
                            VPNPresenter.INSTANCE.afterConnected(server.serverId);
                            sessionStartAndCoundown(server.serverId);
                        }
                    }
                }

                VLog.e("vpn afterConntedShowAd load result:" + success);

            }

        }, System.currentTimeMillis(), AD_WAIT_TIME);

    }

    Disposable pingDisposable;
    String mSessionId;

    private void sessionStartAndCoundown(String serverId) {
        VLog.e("afterConnted");
        final NodeBean nodeBean = new NodeBean();
        nodeBean.serverId = serverId;
        beginCoundown();
        sessionStart(nodeBean, VPNPresenter.INSTANCE.getCurrConnectSession(), true);
    }

    public void sessionPingAndCoundown(String serverId, int addTime, String sessionId) {
        final NodeBean nodeBean = new NodeBean();
        nodeBean.serverId = serverId;
        beginCoundown();
        VLog.e("sessionStart resume:" + addTime);
        nodeBean.sessionId = sessionId;
        sessionStartAction(nodeBean, addTime, false);
        ping(nodeBean);

    }

    public void beginCoundown() {
        VLog.e("beginCoundown");
        VPNPresenter.INSTANCE.addCountdownCallback(new VPNPresenter.CountdownCallback() {
            @Override
            public void countdown(int seconds) {
                if (mCountdownCallback != null) {
                    mCountdownCallback.countdown(seconds);
                }
            }

            @Override
            public void finish() {
                VLog.e("dissconect finish");
                if (mCountdownCallback != null) {
                    mCountdownCallback.finish();
                }
            }
        });


    }

    private void sessionStart(NodeBean nodeBean, long sessoin, boolean hanlderTime) {
        NetService.INSTANCE.seesionStart(nodeBean).subscribe(new Consumer<BaseResponse<StartBean>>() {
            @Override
            public void accept(BaseResponse<StartBean> bean) throws Throwable {

                int addTime = bean.result.addTime;
                VLog.e("sessionStart ok:" + addTime);
                nodeBean.sessionId = bean.result.sessionId;
                if (hanlderTime) {
                    sessionStartAction(nodeBean, addTime, true);
                }
                ping(nodeBean);

            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Throwable {
                throwable.printStackTrace();
                VLog.e("start error:" + throwable.getMessage());
                if (hanlderTime) {
                    sessionStartAction(nodeBean, 45 * 60, true);
                }
                Observable.timer(30, TimeUnit.SECONDS)
                        .subscribeOn(Schedulers.io()) // 在 IO 线程上执行
                        .observeOn(Schedulers.computation()) // 在计算线程上观察
                        .subscribe(
                                aLong -> {
                                    if (VPNPresenter.INSTANCE.isConnected() && sessoin != 0
                                            && sessoin == VPNPresenter.INSTANCE.getCurrConnectSession()) {
                                        VLog.e(" new start");
                                        sessionStart(nodeBean, sessoin, false);
                                    }
                                },
                                throwable1 -> {
                                    // 处理错误
                                    System.err.println("Error: " + throwable.getMessage());
                                }
                        );


            }
        });
    }

    private void sessionStartAction(NodeBean nodeBean, int addTime, boolean saveInfo) {

        VPNDetailInfo info = VPNPresenter.INSTANCE.getConnectedVpnInfoServer();
        if (saveInfo) {
            if (info != null){
                info.addTime = addTime;
                info.startTime = System.currentTimeMillis();
                info.sessionId = nodeBean.sessionId;
                Log.e("setConnectedVpnInfoServer","sessionStartAction:"+info);
                VPNPresenter.INSTANCE.setConnectedVpnInfoServer(info);
            }
            VPNDetailInfo info2 = VPNPresenter.INSTANCE.getLastConnectVPNDetailInfo();
            if (info2 != null){
                info2.addTime = addTime;
                info2.startTime = System.currentTimeMillis();
                info2.sessionId = nodeBean.sessionId;
                VPNPresenter.INSTANCE.setLastConnectVPNDetailInfo(info2);
            }
        } else if (info.startTime != 0) {
            addTime = info.getLeftTime();
        }

        VPNPresenter.INSTANCE.startCountdown(addTime);
        VLog.e("countdown time：" + addTime);
        mSessionId = nodeBean.sessionId;
    }


    private long lastReportTime;

    private void ping(NodeBean bean) {
        if (pingDisposable != null) {
            pingDisposable.dispose();
        }
        lastReportTime = System.currentTimeMillis();
        pingDisposable = Observable.interval(60, 60, TimeUnit.SECONDS) // 每1分钟发射一次
                .observeOn(Schedulers.io()) // 在IO线程执行
                .subscribe(
                        tick -> {
                            long startTime = System.currentTimeMillis();
                            NetService.INSTANCE.seesionPing(bean).subscribe(new Consumer<BaseResponse<PingBean>>() {
                                @Override
                                public void accept(BaseResponse<PingBean> response) throws Throwable {
                                    VLog.e("seesionPing success：" + response.result.userIsLimit);
                                    if (response.result.userIsLimit) {
                                        if (currVPNActionCallback != null) {
                                            VPNPresenter.INSTANCE.afterDisConnect();
                                            currVPNActionCallback.error(VPNApp.getBase().getString(R.string.out_limit));
                                            currVPNActionCallback.disconect(true);
                                        }
                                    }
                                    long diffTime = System.currentTimeMillis() - startTime;
                                    if ( System.currentTimeMillis() - lastReportTime > 30 * 60 * 1000) {
                                        if (diffTime > 800){
                                            Map<String, Object> map = new HashMap<>();
                                            int level = 5;
                                            if (diffTime > 1000){
                                                level = 6;
                                            }
                                            map.put("level", level + "");
                                            VPNDetailInfo detailInfo = VPNPresenter.INSTANCE.getConnectedVpnInfoServer();
                                            if (detailInfo != null){
                                                map.put("country", detailInfo.countryName );
                                                map.put("severid", detailInfo.serverId);
                                            }
                                            VLog.event("Network_Monitor",map);
                                        }
                                        lastReportTime = System.currentTimeMillis();
                                    }
                                }
                            }, new Consumer<Throwable>() {
                                @Override
                                public void accept(Throwable throwable) throws Throwable {
                                    VLog.e("seesionPing fail：" + throwable.getMessage());
                                }
                            });
                        },
                        Throwable::printStackTrace,
                        () -> System.out.println("Completed")
                );
    }

    private void afterDisConnect(String serverId) {
        VPNPresenter.INSTANCE.afterDisConnect();
        clearCurrInfos();
        NodeBean bean = new NodeBean();
        bean.serverId = serverId;
        bean.sessionId = mSessionId;
        if (pingDisposable != null) {
            pingDisposable.dispose();
        }
        NetService.INSTANCE.seesionEnd(bean).subscribe(new Observer<BaseResponse<Void>>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {

            }

            @Override
            public void onNext(@NonNull BaseResponse<Void> voidBaseResponse) {
                VLog.e("seesionEnd success：");
            }

            @Override
            public void onError(@NonNull Throwable e) {
                VLog.e("seesionEnd fail：" + e.getMessage());
                e.printStackTrace();
            }

            @Override
            public void onComplete() {

            }
        });
    }

    public void checkNotifyPerssion() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
                //VPNApp.setInApp(true);
                ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.POST_NOTIFICATIONS}, REQUEST_PERSSION_NOTIFY);
                return;
            }
        }
        DisConnectNotifyHelper.send(VPNApp.getBase());
    }


    private CountdownCallback mCountdownCallback;

    public void setCountdownCallback(CountdownCallback callback) {
        mCountdownCallback = callback;
    }


    public interface VPNActionCallback {
        void connecting();

        void conected();

        void disconect(boolean isError);

        void error(String message);

        void onProcess(String process);

        void trafficUpdated(long txRate, long rxRate);

    }

    private VPNInfoCallback mVPNInfoCallback;

    public void setVPNInfoCallback(VPNInfoCallback callback) {
        mVPNInfoCallback = callback;
    }

    public interface VPNInfoCallback {
        void updateRecommon(VPNDetailInfo vpnDetailInfo);
    }


    public interface CountdownCallback {
        void countdown(int seconds);

        void finish();
    }

    public void addTime(int time) {
        VPNDetailInfo info = VPNPresenter.INSTANCE.getLastConnectVPNDetailInfo();
        if (info == null) {
            return;
        }
        VPNPresenter.INSTANCE.startCountdown(info.getLeftTime() + time);
        info.addTime = info.addTime + time;
        VPNPresenter.INSTANCE.setLastConnectVPNDetailInfo(info);
    }
}
